import logging
from flask_babel import _
from controllers.errors.error import HttpAccountNotFound
from controllers.errors.online_mall.shop_errors import HShopNotFoundError,HShopParamError
from core.entities.account_role import AccountWrap
from extensions.ext_database import db

from models.account import Account
from models.online_mall.shop_msg import (
    ShopStatus,
    MShop,
    MShopApproval
)
from werkzeug.exceptions import InternalServerError
from services.errors.account import NotLoginError
from services.file_service import FileService


class ShopService:
    @staticmethod
    def get_shop_name_list(tenant_id:str)->list[dict]:
        try:
            shops = db.session.query(MShop.id,MShop.name).filter(MShop.tenant_id==tenant_id).all()
            result = [{"id":shop[0],"name":shop[1]} for shop in shops]
            return result
        except Exception as e:
            logging.error(e)
            return []
        
    @staticmethod
    def get_shop_list(tenant_id:str,args)->dict:
        try:
            total = 0
            has_more = False
            query = db.session.query(MShop).filter(MShop.tenant_id==tenant_id)
            total = query.count()
            if 'shop_type' in args and args['shop_type']:
                query = query.filter(MShop.shop_type==int(args['shop_type']))
            if 'industry' in args and args['industry']:
                query = query.filter(MShop.industry==int(args['industry']))
            if 'mobile' in args and args['mobile']:
                query = query.filter(MShop.mobile.like(f"%{args['mobile']}%"))
            if 'service_tel' in args and args['service_tel']:
                query = query.filter(MShop.service_tel.like(f"%{args['service_tel']}%"))
            if 'province' in args and args['province']:
                query = query.filter(MShop.province.like(f"%{args['province']}%"))
            if 'city' in args and args['city']:
                query = query.filter(MShop.city.like(f"%{args['city']}%"))
            if 'district' in args and args['district']:
                query = query.filter(MShop.district.like(f"%{args['district']}%"))
            if 'zip_code' in args and args['zip_code']:
                query = query.filter(MShop.zip_code.like(f"%{args['zip_code']}%"))
            if 'shop_status' in args and args['shop_status']:
                query = query.filter(MShop.shop_status==args['shop_status'])
            transport_type = args.get("transport_type")
            is_distribution = args.get("is_distribution")
            if transport_type is not None:
                query = query.filter(MShop.transport_type==transport_type)
            if is_distribution is not None:
                query = query.filter(MShop.is_distribution==is_distribution)
            page = args.get("page",1)
            page_size = args.get("page_size",10)
            if page and page_size and page >0 and page_size >0:
                query = query.offset((page-1)*page_size).limit(page_size)
                has_more = total > page*page_size
            data = query.all()
            return {
                "total":total,
                "has_more":has_more,
                "data":data
            }
        except Exception as e:
            logging.error(e)
            return {
                "total":0,
                "has_more":False,
                "data":[],
                "error":str(e)
            }

    @staticmethod
    def get_shop_info(shop_id)->MShop:
        shop = db.session.get(MShop,shop_id)
        if not shop:
            raise HShopNotFoundError(shop_id)
        return shop
    
    @staticmethod
    def get_my_shop_info(account:AccountWrap)->dict:
        tenant_id = account.current_tenant_id
        shops = db.session.query(MShop).filter(MShop.tenant_id == tenant_id,
                                       MShop.master_id == account.id).all()
        return {
            'data':shops,
            'total':len(shops)
        }
    
    @staticmethod
    def create_shop(account:AccountWrap,args:dict)->MShop:
        if not account or not isinstance(account,AccountWrap):
            raise NotLoginError()
        if not account.current_tenant_id:
            raise NotLoginError()
        master_id = args.get('master_id')
        if not master_id:
            raise HShopParamError(_("Shop Master ID is required"))
        master = db.session.get(Account,master_id)
        if not master:
            raise HttpAccountNotFound(master_id)
        new_shop = MShop(
            tenant_id = account.current_tenant_id, # type:ignore
            master_id = master_id, # type:ignore
            master_name= master.name, # type:ignore
            shop_status = ShopStatus.NOT_APPROVED,# type:ignore
            created_by = account.id# type:ignore
        )
        ShopService._fill_shop_params(args, new_shop)
        try:
            db.session.add(new_shop)
            db.session.commit()
            return new_shop
        except Exception as e:
            logging.error(e)
            raise InternalServerError(str(e))
        
    @staticmethod
    def update_shop(account:AccountWrap,args:dict)->MShop:
        if not account or not isinstance(account,AccountWrap):
            raise NotLoginError()
        if not account.current_tenant_id:
            raise NotLoginError()
        master_id = args.get('master_id')
        if not master_id:
            raise HShopParamError(_("Shop Master ID is required"))
        master = db.session.get(Account,master_id)
        if not master:
            raise HttpAccountNotFound(master_id)
        shop_id = args.get('id')
        shop = db.session.get(MShop,shop_id)
        if not shop:
            raise HShopNotFoundError(shop_id)
        ShopService._fill_shop_params(args, shop)
        try:
            db.session.commit()
            return shop
        except Exception as e:
            logging.error(e)
            raise InternalServerError(str(e))
        
    @staticmethod
    def delete_shop(account:AccountWrap,args:dict):
        if not account or not isinstance(account,AccountWrap):
            raise NotLoginError()
        if not account.current_tenant_id:
            raise NotLoginError()
        shop_id = args.get('id')
        shop = db.session.get(MShop,shop_id)
        if not shop:
            raise HShopNotFoundError(shop_id)
        try:
            db.session.delete(shop)
            db.session.commit()
        except Exception as e:
            logging.error(e)
            raise InternalServerError(str(e))


    @staticmethod
    def _fill_shop_params(args:dict, new_shop:MShop):
        new_shop.name = args.get('name')
        if not new_shop.name:
            raise HShopParamError(_("Shop Name is required"))
        
        if 'shop_type' in args and args['shop_type']:
            new_shop.shop_type = args['shop_type']
        else:
            new_shop.shop_type = 1

        if 'intro' in args and args['intro']:
            new_shop.intro = args['intro']
        
        if 'notice' in args and args['notice']:
            new_shop.notice = args['notice']

        if 'industry' in args and args['industry']:
            new_shop.industry = args['industry']
        if 'mobile' in args and args['mobile']:
            new_shop.mobile = args['mobile']
        if 'service_tel' in args and args['service_tel']:
            new_shop.service_tel = args['service_tel']
        if 'lat' in args and args['lat']:
            new_shop.lat = float(args['lat'])
            if new_shop.lat > 90 or new_shop.lat < -90:
                raise HShopParamError(_("Latitude must be between -90 and 90."))
        if 'lng' in args and args['lng']:
            new_shop.lng = float(args['lng'])
            if new_shop.lng > 180 or new_shop.lng < -180:
                raise HShopParamError(_("Longitude must be between -180 and 180."))
        
        if 'address' in args and args['address']:
            new_shop.address = args['address']
        if 'province' in args and args['province']:
            new_shop.province = args['province']
        if 'city' in args and args['city']:
            new_shop.city = args['city']
        if 'district' in args and args['district']:
            new_shop.district = args['district']
        if 'zip_code' in args and args['zip_code']:
            new_shop.zip_code = args['zip_code']
        if 'shop_logo_file_id' in args and args['shop_logo_file_id']:
            if FileService.file_exist(args['shop_logo_file_id']):
                new_shop.shop_logo_file_id = args['shop_logo_file_id']
            else:
                raise HShopParamError(_("shop logo file is not found"))
        if 'ShopPhotos' in args and args['ShopPhotos']:
            shop_photos = args['ShopPhotos']
            for photo_file_id in shop_photos:
                if photo_file_id:
                    if FileService.file_exist(photo_file_id):
                        continue
                    else:
                        raise HShopParamError(_("shop photo file is not found")+":"+photo_file_id)
            new_shop.shop_photos = {"items": shop_photos}
        if 'open_time' in args and args['open_time']:
            new_shop.open_time = args['open_time']
        if 'shop_status' in args and args['shop_status']:
            new_shop.shop_status = args['shop_status']
            if new_shop.shop_status not in ShopStatus.choices():
                raise HShopParamError(_("shop status is not valid")+":"+new_shop.shop_status)
        if 'transport_type' in args and args['transport_type'] is not None:
            new_shop.transport_type = args['transport_type']
        if 'fixed_freight' in args and args['fixed_freight']:
            new_shop.fixed_freight = args['fixed_freight']
        if 'full_free_shipping' in args and args['full_free_shipping']:
            new_shop.full_free_shipping = args['full_free_shipping']
        if 'is_distribution' in args and args['is_distribution'] is not None:
            new_shop.is_distribution = args['is_distribution']

    ### APPROVAL
    # @staticmethod
    # def get_approval_list(tenant_id:str,approvaled:bool|None,page:int=-1,page_size:int=-1)->dict:
    #     try:
    #         query = db.session.query(MShop).filter(MShop.tenant_id==tenant_id)
    #         if approvaled is not None:
    #             if approvaled:
    #                 query = query.filter(MShop.shop_status != ShopStatus.NOT_APPROVED.value)
    #             else:
    #                 query = query.filter(MShop.shop_status == ShopStatus.NOT_APPROVED.value)
    #         total = query.count()
    #         has_more = False
    #         if page >0 and page_size >0:
    #             query = query.limit(page_size).offset((page-1)*page_size)
    #             has_more = total > page*page_size
    #         data = query.order_by(MShop.shop_status,MShop.created_at.desc()).all()
    #         return {
    #             "total":total,
    #             "has_more":has_more,
    #             "data":data
    #         }
    #     except Exception as e:
    #         logging.error(e)
    #         return {
    #             "message":str(e),
    #             "code":500
    #         }
    @staticmethod
    def approval_list(shop_id:str)->list[MShopApproval]:
        try:
            shop = db.session.get(MShop,shop_id)
            if not shop:
                raise HShopNotFoundError(shop_id)
            return db.session.query(MShopApproval).filter(MShopApproval.shop_id==shop_id).order_by(MShopApproval.created_at.desc()).all()
        except Exception as e:
            logging.error(e)
        return []

    @staticmethod
    def approval(account:AccountWrap,shop_id:str,content:str,approvaled:bool)->list[MShopApproval]:
        try:
            shop = db.session.get(MShop,shop_id)
            if not shop:
                raise HShopNotFoundError(shop_id)
            if approvaled:
                shop.shop_status = ShopStatus.NOT_OPEN
            else:
                shop.shop_status = ShopStatus.NOT_APPROVED
            db.session.add(MShopApproval(
                shop_id = shop_id, # type:ignore
                approver = account.id, # type:ignore
                approve = approvaled, # type:ignore
                content = content, # type:ignore
            ))
            db.session.commit()
            return db.session.query(MShopApproval).filter(MShopApproval.shop_id==shop_id).order_by(MShopApproval.created_at.desc()).all()
        except Exception as e:
            logging.error(e)
        return []
